package pl.edu.agh.neural.core;

import pl.edu.agh.neural.simple.InputConnection;
import pl.edu.agh.neural.simple.activation.IActivationFunction;
import pl.edu.agh.neural.simple.activation.LinearActivation;

import java.util.Arrays;

public abstract class ConnectedNeuron implements INeuron {

    protected InputConnection[] inputConnections;
    protected IActivationFunction activationFunction;
    protected double value;
    protected double error;
    protected double derivative;
    protected double sum;

    @Override
    public InputConnection[] getInputConnections() {
        return inputConnections;
    }

    @Override
    public double[] getInputConnectionsWeights() {
        double[] weights = new double[inputConnections.length];
        for (int i = 0; i < weights.length; i++) {
            weights[i] = inputConnections[i].getWeight();
        }

        return weights;
    }

    @Override
    public void setInputConnectionsWeights(double[] weights) {
        for (int i = 0; i < weights.length; i++) {
            inputConnections[i].setWeight(weights[i]);
        }
    }

    @Override
    public double[] getInputConnectionsNodesValues() {
        double[] values = new double[inputConnections.length];
        for (int i = 0; i < values.length; i++) {
            values[i] = inputConnections[i].getNeuron().getValue();
        }

        return values;
    }

    @Override
    public double evaluate()
    {
        sum = getSum();
        value = activationFunction.evaluate(sum);
        derivative = activationFunction.evaluateDerivative(sum);
        return value;
    }

    @Override
    public double getValue()
    {
        return value;
    }

    @Override
    public double getDerivative() {
        return derivative;
    }

    protected double getSum()
    {
        double sum = 0.0;
        for (InputConnection inputConnection : inputConnections)
        {
            sum += inputConnection.getNeuron().getValue() * inputConnection.getWeight();
        }
        return sum;
    }

    @Override
    public double getError() {
        return error;
    }

    @Override
    public void setError(double error) {
        this.error = error;
    }

    protected ConnectedNeuron(InputConnection[] inputConnections) {
        this.inputConnections = Arrays.copyOf(inputConnections, inputConnections.length);
        this.activationFunction = new LinearActivation(1.0);
    }
}
